use egui::{Align2, Color32, Margin, Pos2, Rect, Rounding, Stroke, Vec2};
use serde::{Deserialize, Deserializer, Serialize};
use thunderdome::Index;
use uuid::Uuid;

use crate::{
    core::layer::Layer,
    message::{EventBuilder, UiMessageType},
};

#[derive(Serialize, Deserialize, Debug)]
pub struct Widget {
    pub uuid: Uuid,
    pub id: Index,
    pub name: String,
    pub layer: Layer,
    pub active: bool,
    pub width: f32,
    pub height: f32,
    pub margin: Margin,
    pub padding: Margin,
    pub background: Color32,
    pub foreground: Color32,
    pub radius: Rounding,
    pub border: Stroke,
    pub children: Vec<Index>,
    pub parent: Option<Index>,
    pub z_index: u32,
    pub opacity: f32,
    pub font_size: f32,
    pub align: Align2,
    pub position: Pos2,
    pub world_position: Pos2,
}

impl Default for Widget {
    fn default() -> Self {
        Self {
            uuid: Uuid::new_v4(),
            id: Index::DANGLING,
            name: "Widget".to_string(),
            active: true,
            layer: Layer::Default,
            width: 0.0,
            height: 0.0,
            margin: Default::default(),
            padding: Default::default(),
            radius: Default::default(),
            border: Default::default(),
            background: Color32::TRANSPARENT,
            foreground: Color32::BLACK,
            children: Vec::new(),
            parent: None,
            z_index: 1,
            opacity: 1.0,
            font_size: 14.,
            align: Align2::LEFT_TOP,
            position: Pos2::ZERO,
            world_position: Pos2::ZERO,
        }
    }
}

impl Widget {
    pub fn with_name(mut self, name: &str) -> Self {
        self.name = name.to_string();
        self
    }

    pub fn with_active(mut self, active: bool) -> Self {
        self.active = active;
        self
    }

    pub fn with_width(mut self, width: f32) -> Self {
        self.width = width;
        self
    }

    pub fn with_height(mut self, height: f32) -> Self {
        self.height = height;
        self
    }

    pub fn with_background(mut self, background: Color32) -> Self {
        self.background = background;
        self
    }

    pub fn with_foreground(mut self, foreground: Color32) -> Self {
        self.foreground = foreground;
        self
    }

    pub fn with_margin(mut self, margin: Margin) -> Self {
        self.margin = margin;
        self
    }

    pub fn with_padding(mut self, padding: Margin) -> Self {
        self.padding = padding;
        self
    }

    pub fn with_radius(mut self, radius: Rounding) -> Self {
        self.radius = radius;
        self
    }

    pub fn with_border(mut self, border: Stroke) -> Self {
        self.border = border;
        self
    }

    pub fn with_align(mut self, align: Align2) -> Self {
        self.align = align;
        self
    }

    pub fn with_position(mut self, position: Pos2) -> Self {
        self.position = position;
        self
    }

    pub fn with_layer(mut self, layer: Layer) -> Self {
        self.layer = layer;
        self
    }

    pub fn on_event(self, event: UiMessageType, func: Box<dyn Fn(UiMessageType)>) -> EventBuilder {
        EventBuilder::new(self).on_event(event, func)
    }

    pub fn get_rect(&self) -> Rect {
        egui::Rect::from_min_size(
            Pos2::new(
                self.world_position.x + self.margin.left,
                self.world_position.y + self.margin.top,
            ),
            Vec2::new(self.width, self.height),
        )
    }

    pub fn get_size(&self) -> Vec2 {
        Vec2::new(
            self.width
                + self.margin.left
                + self.margin.right
                + self.padding.left
                + self.padding.right,
            self.height
                + self.margin.top
                + self.margin.bottom
                + self.padding.top
                + self.padding.bottom,
        )
    }

    pub fn set_world_position(&mut self, position: Pos2) {
        self.world_position = position;
    }

    pub fn set_id(&mut self, index: Index) {
        self.id = index;
    }

    pub fn set_name(&mut self, name: &str) {
        self.name = name.to_string();
    }

    pub fn set_parent(&mut self, parent: Option<Index>) {
        self.parent = parent;
    }

    pub fn set_layer(&mut self, layer: Layer) {
        self.layer = layer;
    }

    pub fn add_child(&mut self, child: Index) {
        self.children.push(child);
    }

    pub fn remove_child(&mut self, child: Index) {
        self.children.retain(|id| *id != child)
    }
}
